
package deleteroleservice;

import java.io.*;
import java.sql.*;
import java.text.SimpleDateFormat;

import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.ParameterMode;
import java.util.*;

public class DeleteRoleImpl implements DeleteRoleIF {
    

	
	/* (non-Javadoc)
	 * @see deleteroleservice.DeleteRoleIF#deleteRole(int, java.lang.String)
	 */
	public boolean deleteRole(int comId, String roleName)
	{
	
		//define the driver to use 
	      String driver = "org.apache.derby.jdbc.ClientDriver";
	    //the database name  
	      String dbName="RSSdb";
	    //define the Derby connection URL to use 
	      String connectionURL = "jdbc:derby://localhost:1527/" + dbName;
	    
	      Connection conn = null;
	      Statement s;
	      Statement s1;
	      Statement s2;
	      ResultSet rs;
	      ResultSet rs1;
	       
	    //load derby driver
	      try{
	          Class.forName(driver); 
	          System.out.println(driver + " loaded. ");
	          
	      } catch(java.lang.ClassNotFoundException e)     {
	          System.err.print("ClassNotFoundException: ");
	          System.err.println(e.getMessage());
	          System.out.println("\n    >>> Please check your CLASSPATH variable   <<<\n");
	      }
	      
		try{

			conn = DriverManager.getConnection(connectionURL);
			System.out.println("Connected to database " + dbName);
			
			s=conn.createStatement();
			s1=conn.createStatement();
			
			//verify the target role exists
			String sqlRole = "SELECT * FROM roleDictionary WHERE roleName='"+roleName+"'";
			rs = s.executeQuery(sqlRole);
			
			if(!rs.next()){
				conn.close();
				System.out.println("There is no role exists in Role Dictionary named: "+ roleName+"!");
				return false;
			}
			
		//find all role owners' addresses
			
			//construct sql: get all role owner's id 
			String sqlRoleOwnerId = "SELECT lid FROM roleGrant WHERE roleName='"+roleName+"' GROUP BY lid";
			
			//execute query
			rs = s.executeQuery(sqlRoleOwnerId);
				
			
			//if there are some role owner exist, invoke their voteForDelete services.
			while(rs.next()){
				//find addresses according to Ids
				String sqlAddress="SELECT address FROM company WHERE lid="+rs.getInt("lid");
				rs1=s1.executeQuery(sqlAddress);
				rs1.next();
				String serviceAddress=rs1.getString("address");
				
				//use DII metohd to invoke vote services for delete
				boolean voteResult=false;
				voteResult=invokeVoteForDeleteService(comId, roleName, serviceAddress);
				//If there is one role owner does not vote, delete fails
				if(!voteResult){
					conn.close();
					System.out.println("There is some role owner do not support to delete the role named: "+roleName+"!");
					return false;
				}
			}
			
//either there is no role owner, or role owners all support to delete the target role, RSS invoke all participant's 
//DeleteRoleInHierarchy services
			
			//construct sql: find all participants in the traceability network
			String sqlAllParticipants="SELECT address FROM company";
			rs = s.executeQuery(sqlAllParticipants);
			while(rs.next()){
				String address = rs.getString("address");
				invokeDeleteRoleInHierarchyService(roleName, address);
			}
			
			//programmer may use their own way to delete the target role
			hookDeleteRole(roleName);
//			String sqlDeleteRole = "DELETE FROM roleDictionary WHERE roleName='"+roleName+"'";
//			int row = s1.executeUpdate(sqlDeleteRole);
//			System.out.println(row+" rows has been deleted");
//			System.out.println("Target role: "+roleName+" has been deleted");
			
			//close connection
			conn.close();			
				
		}catch(Exception e){
			e.printStackTrace();	
		}
		return true;
    }
	
	//define DII method to VoteForDeleteService
	/**
	 * A method constructing DII 
	 * @param comId					Applicant company's id.
	 * @param roleName				Name of the target role.
	 * @param serviceProviderAddr	Address of service provider company.
	 * @return						true if voting company supports for role delete.
	 */
	public boolean invokeVoteForDeleteService(int comId, String roleName, String serviceProviderAddr){
		String qnameService = "VoteForDeleteService";
	    String qnamePort = "VoteForDeleteIF";
	    String BODY_NAMESPACE_VALUE = "urn:Foo";
	    String ENCODING_STYLE_PROPERTY = "javax.xml.rpc.encodingstyle.namespace.uri";
	    String NS_XSD = "http://www.w3.org/2001/XMLSchema";
	    String URI_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";
	    
	    		//voting result
	    		boolean result=false;
	    		
				//construct complete endPointAddress
		   		String endPointAddr = serviceProviderAddr+"VoteForDelete/vote";
		        System.out.println("Endpoint address = " + endPointAddr);

		        try {
		        	//create call
		            ServiceFactory factory = ServiceFactory.newInstance();
		            Service service = factory.createService(new QName(qnameService));
		            Call call = service.createCall(new QName(qnamePort));

		            call.setTargetEndpointAddress(endPointAddr);
		            call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
		            call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
		            call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);

		            //set data types
		            QName QNAME_TYPE_STRING = new QName(NS_XSD, "string");
		            QName QNAME_TYPE_BOOLEAN = new QName(NS_XSD, "boolean");
		            QName QNAME_TYPE_INT = new QName(NS_XSD, "int");

		            //set return type
		            call.setReturnType(QNAME_TYPE_BOOLEAN);

//		            set access point method for service
		            call.setOperationName(new QName(BODY_NAMESPACE_VALUE, "voteForDelete"));
//		            //set parameters
		            call.addParameter("int_1", QNAME_TYPE_INT, ParameterMode.IN);
		            call.addParameter("String_2", QNAME_TYPE_STRING, ParameterMode.IN);

		            
		            Object[] params = {comId, roleName};

		            //invoke the target method with constructed parameter(s)
		            System.out.println("Accessing service on: "+endPointAddr+"...");
		            result = (Boolean) call.invoke(params);
		            System.out.println("Vote for delete result from "+endPointAddr+"is "+result);


		        } catch (Exception ex) {
		            ex.printStackTrace();
		        }
		        return result;
		    }
	
//	define DII method to DeleteRoleInHierarchy
	/**
	 * A method constructing DII 
	 * @param roleName				Name of the target role.
	 * @param serviceProviderAddr	Address of service provider company.
	 * @return						true if voting company supports for role delete.
	 */
	public boolean invokeDeleteRoleInHierarchyService(String roleName, String serviceProviderAddr){
		String qnameService = "DeleteRoleInHierarchyService";
	    String qnamePort = "DeleteRoleInHierarchyIF";
	    String BODY_NAMESPACE_VALUE = "urn:Foo";
	    String ENCODING_STYLE_PROPERTY = "javax.xml.rpc.encodingstyle.namespace.uri";
	    String NS_XSD = "http://www.w3.org/2001/XMLSchema";
	    String URI_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";
	    
	    		//delete result
	    		boolean result=false;
				//construct complete endPointAddress
		   		String endPointAddr = serviceProviderAddr+"DeleteRoleInHierarchy/delete";
		        System.out.println("Endpoint address = " + endPointAddr);

		        try {
		        	//create call
		            ServiceFactory factory = ServiceFactory.newInstance();
		            Service service = factory.createService(new QName(qnameService));
		            Call call = service.createCall(new QName(qnamePort));

		            call.setTargetEndpointAddress(endPointAddr);
		            call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
		            call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
		            call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);

		            //set data types
		            QName QNAME_TYPE_STRING = new QName(NS_XSD, "string");
		            QName QNAME_TYPE_BOOLEAN = new QName(NS_XSD, "boolean");

		            //set return type
		            call.setReturnType(QNAME_TYPE_BOOLEAN);

//		            set access point method for service
		            call.setOperationName(new QName(BODY_NAMESPACE_VALUE, "deleteRoleInHierarchy"));
//		            //set parameters
		            call.addParameter("String_1", QNAME_TYPE_STRING, ParameterMode.IN);
		            
		            String[] params = {roleName};

		            //invoke the target method with constructed parameter(s)
		            System.out.println("Accessing service on: "+endPointAddr+"...");
		            result = (Boolean) call.invoke(params);
		            System.out.println("Delete result from "+endPointAddr+"is "+result);


		        } catch (Exception ex) {
		            ex.printStackTrace();
		        }
		        return result;
		    }
	
	//programmers can use this hook method to do the role delete in their own ways
	boolean hookDeleteRole(String roleName){
		return true;
	}
}
